package com.cpr.rwqd_sjjn.service;

import com.cpr.rwqd_sjjn.entity.User;
import com.cpr.rwqd_sjjn.repository.UserRepository;
import com.cpr.rwqd_sjjn.request.RegisterRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {

    private final PasswordEncoder passwordEncoder;
    private final UserRepository userRepository;
    private final JavaMailSender mailSender;
    private static final Logger log = LoggerFactory.getLogger(UserService.class);

    // 存储验证码及其生成时间戳
    private Map<String, VerificationCode> verificationCodes = new ConcurrentHashMap<>();

    @Autowired
    public UserService(PasswordEncoder passwordEncoder, UserRepository userRepository, JavaMailSender mailSender) {
        this.passwordEncoder = passwordEncoder;
        this.userRepository = userRepository;
        this.mailSender = mailSender;

        // 启动定时任务，每分钟清理一次过期验证码
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(this::cleanupExpiredCodes, 1, 1, TimeUnit.MINUTES);
    }

    /**
     * 每分钟自动批量清除过期验证码
     */
    private void cleanupExpiredCodes() {
        long currentTime = System.currentTimeMillis(); // 获取当前时间戳
        long expirationThreshold = currentTime - TimeUnit.MINUTES.toMillis(5); // 计算过期阈值（5分钟前）

        // 批量移除过期验证码
        verificationCodes.entrySet().removeIf(entry -> entry.getValue().isExpired(currentTime));

        log.info("已批量清除过期验证码，当前剩余验证码数量: {}", verificationCodes.size());
    }

    /**
     * 注册用户
     *
     * @param registerRequest 注册请求
     * @return 注册结果
     */
    public String register(RegisterRequest registerRequest) {
        User user = registerRequest.getUser();
        String emailVerificationCode = registerRequest.getEmailVerificationCode();

        // 校验密码格式
        if (!validatePasswordFormat(user.getPassword())) {
            return "密码格式不符合要求：8-20位，至少包含大写字母、小写字母、数字中的两种，且不能包含中文字符";
        }

        Optional<User> optionalUserByNumber = userRepository.findByNumber(user.getNumber());
        Optional<User> emailCheck = userRepository.findByEmail(user.getEmail());

        // 检查号码是否已存在且邮箱不为空
        if (optionalUserByNumber.isPresent()) {
            User existingUser = optionalUserByNumber.get();
            if (existingUser.getEmail() != null && !existingUser.getEmail().isEmpty()) {
                return "该号码已注册";
            }
        }

        // 检查邮箱是否已被其他用户绑定
        if (emailCheck.isPresent() && (!optionalUserByNumber.isPresent() || !emailCheck.get().getNumber().equals(user.getNumber()))) {
            return "该邮箱已被其他用户绑定";
        }

        // 验证验证码是否正确
        if (!verifyEmailCode(user.getEmail(), emailVerificationCode)) {
            return "验证码错误或已失效，请重新获取验证码";
        }

        // 注册新用户或更新现有用户
        if (!optionalUserByNumber.isPresent()) {
            User newUser = new User();
            newUser.setNumber(user.getNumber());
            newUser.setName(user.getName());
            newUser.setEmail(user.getEmail());
            newUser.setPassword(passwordEncoder.encode(user.getPassword())); // 加密密码
            newUser.setRoles(2); // 默认角色为2
            userRepository.save(newUser);
            return "注册成功";
        } else {
            User existingUser = optionalUserByNumber.get();
            existingUser.setName(user.getName());
            existingUser.setEmail(user.getEmail());
            existingUser.setPassword(passwordEncoder.encode(user.getPassword())); // 更新时也加密密码
            userRepository.save(existingUser);
            return "注册成功";
        }
    }

    /**
     * 修改密码
     *
     * @param email      用户邮箱
     * @param newPassword 新密码
     * @param code       验证码
     * @return 修改结果
     */
    public String changePassword(String email, String newPassword, String code) {
        // 校验密码格式
        if (!validatePasswordFormat(newPassword)) {
            return "密码格式不符合要求：8-20位，至少包含大写字母、小写字母、数字中的两种，且不能包含中文字符";
        }

        // 通过邮箱查找用户
        Optional<User> optionalUser = userRepository.findByEmail(email);

        // 如果用户不存在，返回错误信息
        if (!optionalUser.isPresent()) {
            return "未找到与该邮箱关联的用户";
        }

        // 验证验证码是否正确
        if (!verifyEmailCode(email, code)) {
            return "验证码错误或已失效，请重新获取验证码";
        }

        // 获取用户并更新密码（加密存储）
        User user = optionalUser.get();
        user.setPassword(passwordEncoder.encode(newPassword)); // 加密新密码
        userRepository.save(user);

        return "密码修改成功";
    }

    public Map<String, Object> loginByNumberAndPassword(String number, String password) {
        Optional<User> optionalUser = userRepository.findByNumber(number);
        if (!optionalUser.isPresent()) {
            throw new RuntimeException("该号码未注册");
        }
        User user = optionalUser.get();

        // 使用 PasswordEncoder 的 matches 方法比较原始密码和加密后的密码
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new RuntimeException("密码错误，可尝试邮箱登录");
        }

        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("userId", user.getId());
        result.put("name", user.getName());
        result.put("roles", user.getRoles());
        return result;
    }

    public Map<String, Object> loginByEmailAndCode(String email, String code) {
        Optional<User> userOptional = userRepository.findByEmail(email);
        Map<String, Object> response = new HashMap<>();

        if (!userOptional.isPresent()) {
            response.put("status", "error");
            response.put("message", "请先注册邮箱");
            return response;
        }

        User user = userOptional.get();

        // 检查验证码是否为空
        if (code == null || code.trim().isEmpty()) {
            sendVerificationCode(email); // 发送验证码
            response.put("status", "info");
            response.put("message", "验证码已发送，请查收邮件");
            return response;
        }

        // 验证验证码
        if (verifyEmailCode(email, code)) {
            // 登录成功，构建返回结果
            response.put("status", "success");
            response.put("message", "登录成功");
            response.put("userId", user.getId());
            response.put("name", user.getName());
            response.put("roles", user.getRoles());
            return response;
        } else {
            response.put("status", "error");
            response.put("message", "验证码错误或已过期");
            return response;
        }
    }

    /**
     * 发送验证码到指定邮箱
     *
     * @param email 用户邮箱
     */
    public void sendVerificationCode(String email) {
        Random random = new Random();
        String code = String.format("%06d", random.nextInt(1000000));
        verificationCodes.put(email, new VerificationCode(code));

        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("3825425049@qq.com");  // 替换为你的发件邮箱地址
        message.setTo(email);
        message.setSubject("您的验证码");
        message.setText("您的验证码是: " + code + "。有效期为5分钟。");

        mailSender.send(message);
        log.info("验证码已发送至邮箱: {}", email);
    }

    /**
     * 验证邮箱验证码是否有效
     *
     * @param email 用户邮箱
     * @param code  验证码
     * @return 是否有效
     */
    public boolean verifyEmailCode(String email, String code) {
        VerificationCode storedCode = verificationCodes.get(email);

        if (storedCode != null) {
            if (storedCode.isExpired()) {
                // 如果验证码已过期，删除验证码
                verificationCodes.remove(email);
                log.info("验证码已过期并被清除: {}", email);
                return false;
            }

            if (storedCode.isValid(code)) {
                // 验证成功后删除验证码
                verificationCodes.remove(email);
                log.info("验证码验证成功并被清除: {}", email);
                return true;
            }
        }

        log.warn("未找到验证码或验证码无效: {}", email);
        return false;
    }



    /**
     * 校验密码格式
     *
     * @param password 密码
     * @return 是否符合要求
     */
    private boolean validatePasswordFormat(String password) {
        // 定义正则表达式规则
        String regexLength = ".{8,20}"; // 长度为8到20位
        String regexUppercase = "[A-Z]"; // 包含大写字母
        String regexLowercase = "[a-z]"; // 包含小写字母
        String regexDigit = "[0-9]"; // 包含数字
        String regexChinese = "[\u4e00-\u9fa5]"; // 包含中文字符

        // 检查密码是否符合长度要求
        if (!password.matches(regexLength)) {
            return false;
        }

        // 检查密码是否包含至少两种字符类型
        int characterTypeCount = 0;
        if (password.matches(".*" + regexUppercase + ".*")) characterTypeCount++;
        if (password.matches(".*" + regexLowercase + ".*")) characterTypeCount++;
        if (password.matches(".*" + regexDigit + ".*")) characterTypeCount++;

        if (characterTypeCount < 2) {
            return false;
        }

        // 检查密码是否包含中文字符
        if (password.matches(".*" + regexChinese + ".*")) {
            return false;
        }

        return true; // 密码格式正确
    }

    /**
     * 内部类：验证码
     */
    private static class VerificationCode {
        private String code;
        private long timestamp;

        public VerificationCode(String code) {
            this.code = code;
            this.timestamp = System.currentTimeMillis(); // 记录生成时间
        }

        public String getCode() {
            return code;
        }

        /**
         * 验证验证码是否有效
         *
         * @param inputCode 输入的验证码
         * @return 是否有效
         */
        public boolean isValid(String inputCode) {
            long currentTime = System.currentTimeMillis();
            long validPeriod = 5 * 60 * 1000; // 5分钟的有效期（毫秒）
            return code.equals(inputCode) && (currentTime - timestamp <= validPeriod);
        }

        /**
         * 判断验证码是否过期
         *
         * @param currentTime 当前时间戳
         * @return 是否过期
         */
        public boolean isExpired(long currentTime) {
            long validPeriod = 5 * 60 * 1000; // 5分钟的有效期（毫秒）
            return (currentTime - timestamp > validPeriod);
        }

        /**
         * 判断验证码是否过期（默认使用当前时间戳）
         *
         * @return 是否过期
         */
        public boolean isExpired() {
            return isExpired(System.currentTimeMillis());
        }
    }
}